package com.superquan.selfstudybootmybatis.utils.encrypt.md5;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

public class SignUtils {
    private static final Logger logger = LoggerFactory.getLogger(SignUtils.class);

    public static String signOfGet(Map<String, String[]> requestParamMap) throws NoSuchAlgorithmException {
        if (requestParamMap == null) {
            requestParamMap = new HashMap<>();
        }
        Map<String, Object[]> signParamMap = new HashMap<>(requestParamMap);
        List<String> requestParamKeys = new ArrayList<>(signParamMap.keySet());
        requestParamKeys.sort(String::compareTo);
        StringBuilder signStr = new StringBuilder();
        for (String requestParamKey : requestParamKeys) {
            List<String> requestParamValues = Arrays.asList(signParamMap.get(requestParamKey)).stream().map(Object::toString).collect(Collectors.toList());
            requestParamValues.sort(String::compareTo);
            for (Object requestParamValue : requestParamValues) {
                signStr.append(requestParamKey).append("=").append(requestParamValue.toString()).append("&");
            }
        }
        signStr.deleteCharAt(signStr.length() - 1);
        logger.info("getsignstr: {}", signStr);
        return MD5.getMD5(signStr.toString());
    }

    public static String signOfPost(Map<String, String[]> requestParamMap, JSON bodyJSON) throws NoSuchAlgorithmException {
        if (requestParamMap == null) {
            requestParamMap = new HashMap<>();
        }
        Map<String, String[]> signMap = new HashMap<>(requestParamMap);
        if (bodyJSON instanceof JSONArray) {
            String bodyStr = signStrOfBody((JSONArray) bodyJSON);
            signMap.put("body", new String[]{bodyStr});
        }
        if (bodyJSON instanceof JSONObject) {
            String bodyStr = signStrOfBody((JSONObject) bodyJSON);
            signMap.put("body", new String[]{bodyStr});
        }
        return signOfGet(signMap);
    }

    private static String signStrOfBody(JSONObject bodyJSON) {
        List<String> bodyKeyList = new ArrayList<>(bodyJSON.keySet());
        bodyKeyList.sort(String::compareTo);
        StringBuilder signStr = new StringBuilder("{");
        for (String bodyKey : bodyKeyList) {
            Object bodyVal = bodyJSON.get(bodyKey);
            if (bodyVal instanceof JSONObject) {
                String bodyValStr = signStrOfBody((JSONObject) bodyVal);
                signStr.append(bodyKey).append(":").append(bodyValStr);
            } else if (bodyVal instanceof JSONArray) {
                String bodyValStr = signStrOfBody((JSONArray) bodyVal);
                signStr.append(bodyKey).append(":").append(bodyValStr);
            } else {
                signStr.append(bodyKey).append(":").append(bodyVal.toString());
            }
            signStr.append(",");
        }
        signStr.deleteCharAt(signStr.length() - 1);
        signStr.append("}");
        logger.info("arraysingstr: {}", signStr);
        return signStr.toString();
    }

    private static String signStrOfBody(JSONArray bodyJSONArray) {
        StringBuilder signStr = new StringBuilder("[");
        for (Object bodyJSON : bodyJSONArray) {
            if (bodyJSON instanceof JSONArray) {
                String bodyJSONArrStr = signStrOfBody(bodyJSONArray);
                signStr.append(bodyJSONArrStr).append(",");
            } else if (bodyJSON instanceof JSONObject) {
                String bodyJSONArrStr = signStrOfBody((JSONObject) bodyJSON);
                signStr.append(bodyJSONArrStr).append(",");
            } else {
                signStr.append(bodyJSON.toString()).append(",");
            }
        }
        signStr.deleteCharAt(signStr.length() - 1);
        signStr.append("]");
        logger.info("arraysingstr: {}", signStr);
        return signStr.toString();
    }

}
